/*
 * Copyright (c) 2020 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * introduction:
 * Mrobot UnionDevices V2 版本  
 *  V2 版本  植物浇水机 water_mqtt.c 支持云端、机器人双通道控制
 * 新增：温湿度检测、烟雾检测功能；
 * 数据分两路上报：1. 传给给机器人，机器人再上传至APP，超过阈值，振动报警提示用户
 *                 2. 传给云服务器，在页面展示 
 * 每台互联设备 对应fan_mqtt.c door_mqtt.c  lamb_mqtt.c  water_mqtt.c 编译记得修改 BUILD.gn
 * 示例代码给出了water_mqtt.c 其他设备根据其自行修改。
 * data:2022.05.30 HelloKun 优化
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "wifi_connect.h"
#include "MQTTClient.h"

#include "wifiiot_errno.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_adc.h"
#include "wifiiot_uart.h"
#include "wifiiot_pwm.h"
#include "hi_uart.h"

#include "mq2_mqtt.h" // 温湿度、烟雾
#include <math.h>

#define UART_BUFF_SIZE 1000
#define MQTT_BUFF_SIZE 1000
#define UART_TIMEOUT 10
#define WATER_TASK_STARCK 10240
#define DANGER_TEMP 80
#define DANGER_PPM 5000
#define PUMP_WORK 30000
#define PUMP_STOP 10
#define PWM_SEQ 40000
#define TASK_TIME 200
#define MQTT_CMD_TIME 2000
#define COUNT_MAX 1000
#define MQTT_QOS2 2
#define MQTT_PORT 1883
#define MQTT_IP "192.168.1.1"
#define WIFI_NAME "r1"
#define WIFI_SWD "88888889"
#define WAIT_MSG '5'
typedef enum
{
    FAN_CLOSE0 = 48, // '0'
    FAN_DEVICE_1,     // '1'
    FAN_LEV_1 = 49,
    FAN_LEV_2,
    FAN_LEV_3,
} fan_status;

typedef enum
{
    DOOR_OPEN_1 = 49, // '1'
    DOOR_DEVICE_2,      // '2'
} door_status;

typedef enum
{
    LAMB_CLOSE0 = 48,    // '0'
    LAMB_DEVICE_3 = 51, // '3'
    LAMB_LEV_1 = 49,
    LAMB_LEV_2,
    LAMB_LEV_3
} lamb_status;

typedef enum
{
    WATER_OPEN_1 = 49,     // '1'
    WATER_DEVICE_4 = 52, // '4'
} water_status;

static const char *data = "MRobot_water\r\n";
uint8_t uart_buff[UART_BUFF_SIZE] = {'0'};
uint8_t *uart_buff_ptr = uart_buff;
char mqtt_buff[MQTT_BUFF_SIZE] = {0};
char water_union_data[30] = {0}; // 互联设备中转消息
typedef struct
{
    float ppm_val;
    float temp_val;
    float humi_val;

} Water_Data_Typedef;
Water_Data_Typedef EnvData;

static unsigned char sendBuf[1000];
static unsigned char readBuf[1000];

Network network;

void messageArrived(MessageData *data)
{
    printf("Message arrived on topic %.*s: %.*s\n", data->topicName->lenstring.len, data->topicName->lenstring.data,
           data->message->payloadlen, data->message->payload);
    strcpy(mqtt_buff, data->message->payload);
    printf("mqtt_buff%s \n", mqtt_buff);
}

static void MyUartInit(void)
{
    uint32_t ret;
    WifiIotUartAttribute uart_attr = {
        .baudRate = 115200,
        .dataBits = 8,
        .stopBits = 1,
        .parity = 0,
    };

    // Initialize uart driver
    ret = UartInit(WIFI_IOT_UART_IDX_1, &uart_attr, NULL);
    if (ret != WIFI_IOT_SUCCESS)
    {
        printf("Failed to init uart! Err code = %d\n", ret);
        return;
    }
}
static void WaterInit(void)
{
    GpioInit();
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_8, WIFI_IOT_IO_FUNC_GPIO_8_PWM1_OUT);
    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_8, WIFI_IOT_GPIO_DIR_OUT);
    PwmInit(WIFI_IOT_PWM_PORT_PWM1); // Beep Alarm

    GpioInit();
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_14, WIFI_IOT_IO_FUNC_GPIO_14_GPIO);
    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_14, WIFI_IOT_GPIO_DIR_OUT); // water motor

    usleep(TASK_TIME * 5000); // wait one seconds for sensor initial
    SensorInit();
}
static void WaterCtr(void)
{
    hi_uart_read_timeout(WIFI_IOT_UART_IDX_1, uart_buff_ptr, UART_BUFF_SIZE, UART_TIMEOUT);
    printf("Uart1 read water data:%s \n", uart_buff_ptr);
    if ((uart_buff[0] == WATER_DEVICE_4) && (uart_buff[1] == WATER_OPEN_1))
    {
        GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_14, WIFI_IOT_GPIO_VALUE1);
        osDelay(80);
        PwmStop(WIFI_IOT_PWM_PORT_PWM1); // 浇水小段时间就够
        GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_14, WIFI_IOT_GPIO_VALUE0);
        uart_buff[0] = WAIT_MSG; // 防止一直浇水
        printf("watering 500ms done\n");
    }
    else
    {
        printf("******* No water 1 *****\n");
        PwmStop(WIFI_IOT_PWM_PORT_PWM1);
    }

    if ((mqtt_buff[0] == WATER_DEVICE_4) && (mqtt_buff[1] == WATER_OPEN_1))
    {
        GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_14, WIFI_IOT_GPIO_VALUE1);
        osDelay(80);
        PwmStop(WIFI_IOT_PWM_PORT_PWM1); // 浇水500ms就够
        GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_14, WIFI_IOT_GPIO_VALUE0);
        printf("watering 500ms done\n");
    }
    else
    {
        printf("******* No Water 2 *****\n");
        PwmStop(WIFI_IOT_PWM_PORT_PWM1);
    }
}

static void Water_Union(void)
{
    printf("Uart1 read water data:%s \n", uart_buff_ptr);
    // fan
    if ((uart_buff[0] == FAN_DEVICE_1) && (uart_buff[1] == FAN_CLOSE0))
    {
        strcpy(water_union_data, "turn off fan");
        printf("turn off fan \n");
        return;
    }
    if ((uart_buff[0] == FAN_DEVICE_1) && (uart_buff[1] == FAN_LEV_1))
    {
        strcpy(water_union_data, "turn on fan lev1");
        printf("turn on fan lev1 \n");
        return;
    }
    if ((uart_buff[0] == FAN_DEVICE_1) && (uart_buff[1] == FAN_LEV_2))
    {
        strcpy(water_union_data, "turn on fan lev2");
        printf("turn on fan lev2 \n");
        return;
    }
    if ((uart_buff[0] == FAN_DEVICE_1) && (uart_buff[1] == FAN_LEV_3))
    {
        strcpy(water_union_data, "turn on fan lev3");
        printf("turn on fan lev3 \n");
        return;
    }

    // door
    if ((uart_buff[0] == DOOR_DEVICE_2) && (uart_buff[1] == DOOR_OPEN_1))
    {
        strcpy(water_union_data, "open door");
        printf("open door \n");
        return;
    }

    // lamb
    if ((uart_buff[0] == LAMB_DEVICE_3) && (uart_buff[1] == LAMB_CLOSE0))
    {
        strcpy(water_union_data, "turn off lamb");
        printf("turn off lamb \n");
        return;
    }
    if ((uart_buff[0] == LAMB_DEVICE_3) && (uart_buff[1] == LAMB_LEV_1))
    {
        strcpy(water_union_data, "turn on lamb lev1");
        printf("turn on lamb lev1 \n");
        return;
    }
    if ((uart_buff[0] == LAMB_DEVICE_3) && (uart_buff[1] == LAMB_LEV_2))
    {
        strcpy(water_union_data, "turn on lamb lev2");
        printf("turn on lamb lev2 \n");
        return;
    }
    if ((uart_buff[0] == LAMB_DEVICE_3) && (uart_buff[1] == LAMB_LEV_3))
    {
        strcpy(water_union_data, "turn on lamb lev3");
        printf("turn on lamb lev3 \n");
        return;
    }
    return;
}
// 环境监测
void EnvironmentDetc(void)
{
    if ((EnvData.ppm_val > DANGER_PPM) || (EnvData.temp_val > DANGER_TEMP))
    {
        printf("******* Enviroment statues is INNORMAL. BEPP is Alarming *****\n");
        PwmStart(WIFI_IOT_PWM_PORT_PWM1, PUMP_WORK, PWM_SEQ);
        osDelay(TASK_TIME);
    }
    else
    {
        printf("******* No Alarm *****\n");
        PwmStop(WIFI_IOT_PWM_PORT_PWM1);
    }
}

static void MQTT_WaterTask(void)
{
    WifiConnect(WIFI_NAME, WIFI_SWD);
    printf("Starting ...\n");
    int rc, count = 0;
    MQTTClient client;

    NetworkInit(&network);
    printf("NetworkConnect  ...\n");

    MyUartInit();
    WaterInit();

begin:
    NetworkConnect(&network, MQTT_IP, MQTT_PORT);
    printf("MQTTClientInit  ...\n");
    MQTTClientInit(&client, &network, MQTT_CMD_TIME, sendBuf, sizeof(sendBuf), readBuf, sizeof(readBuf));

    MQTTString clientId = MQTTString_initializer;
    clientId.cstring = "MRobot_water";

    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.clientID = clientId;
    data.willFlag = 0;
    data.MQTTVersion = 3;
    data.keepAliveInterval = 0;
    data.cleansession = 1;

    printf("MQTTConnect  ...\n");
    rc = MQTTConnect(&client, &data);
    if (rc != 0)
    {
        printf("MQTTConnect: %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        osDelay(TASK_TIME);
        goto begin;
    }

    printf("MQTTSubscribe  ...\n");
    rc = MQTTSubscribe(&client, "web_water_btn", MQTT_QOS2, messageArrived);
    if (rc != 0)
    {
        printf("MQTTSubscribe: %d\n", rc);
        osDelay(TASK_TIME);
        goto begin;
    }

    while (++count)
    {
        Water_Union();
        WaterCtr(); // 串口、mqtt数据控制浇水；MRobot控制--water-->--mqtt---UnionDevices  一生万物

        AHT20_StartMeasure();
        AHT20_GetMeasureResult(&EnvData.temp_val, &EnvData.humi_val);
        EnvData.ppm_val = Get_MQ2_PPM();
        printf("humity: %.2f\n", EnvData.humi_val);
        printf("temperture: %.2f\n", EnvData.temp_val);
        printf("mq2 ppm: %.2f\n", EnvData.ppm_val);

        EnvironmentDetc();
        char payload_humi[30];
        char payload_temp[30];
        char payload_ppm[30];

        MQTTMessage message_humi;
        message_humi.qos = MQTT_QOS2;
        message_humi.retained = 0;
        message_humi.payload = payload_humi;
        sprintf(payload_humi, "humidity%.2f", EnvData.humi_val);
        message_humi.payloadlen = strlen(payload_humi);

        MQTTMessage message_temp;
        message_temp.qos = MQTT_QOS2;
        message_temp.retained = 0;
        message_temp.payload = payload_temp;
        sprintf(payload_temp, "temperture%.2f", EnvData.temp_val);
        message_temp.payloadlen = strlen(payload_temp);

        MQTTMessage message_mq2;
        message_mq2.qos = MQTT_QOS2;
        message_mq2.retained = 0;
        message_mq2.payload = payload_ppm;
        sprintf(payload_ppm, "mq2_ppm%.2f", EnvData.ppm_val);
        message_mq2.payloadlen = strlen(payload_ppm);

        char payload_water_union[30];     // 互联设备中转消息
        MQTTMessage message_water_union; // 云端控制
        message_water_union.qos = MQTT_QOS2;
        message_water_union.retained = 0;
        message_water_union.payload = payload_water_union;
        sprintf(payload_water_union, "%s", water_union_data);
        message_water_union.payloadlen = strlen(payload_water_union);

        if ((rc = MQTTPublish(&client, "water_humi", &message_humi)) != 0)
        {
            printf("Return code from MQTT publish is %d\n", rc);
            NetworkDisconnect(&network);
            MQTTDisconnect(&client);
            goto begin;
        }

        if ((rc = MQTTPublish(&client, "water_temp", &message_temp)) != 0)
        {
            printf("Return code from MQTT publish is %d\n", rc);
            NetworkDisconnect(&network);
            MQTTDisconnect(&client);
            goto begin;
        }

        if ((rc = MQTTPublish(&client, "water_mq2", &message_mq2)) != 0)
        {
            printf("Return code from MQTT publish is %d\n", rc);
            NetworkDisconnect(&network);
            MQTTDisconnect(&client);
            goto begin;
        }
        if ((rc = MQTTPublish(&client, "water_union", &message_water_union)) != 0)
        {
            printf("Return code from MQTT publish is %d\n", rc);
            NetworkDisconnect(&network);
            MQTTDisconnect(&client);
            goto begin;
        }

        uart_buff[0] = WAIT_MSG;
        mqtt_buff[0] = WAIT_MSG; // Wait next refresh data. All command only run once!
        printf("----- count = %d ------\r\n", count);
        if (count > COUNT_MAX)
        {
            count = 1;
        }
        strcpy(water_union_data, "niubility");
    }
}
static void MQTT_Water(void)
{
    osThreadAttr_t attr;

    attr.name = "MQTT_WaterTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = WATER_TASK_STARCK;
    attr.priority = osPriorityNormal;

    if (osThreadNew((osThreadFunc_t)MQTT_WaterTask, NULL, &attr) == NULL)
    {
        printf("[MQTT_Water] Falied to create MQTT_WaterTask!\n");
    }
}
APP_FEATURE_INIT(MQTT_Water);
